package com.pro.framework.api.util;

import com.pro.framework.api.FrameworkConst;
import com.pro.framework.api.enums.EnumTimeUnit;
import com.pro.framework.api.util.inner.TimeDifference;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

public class DateUtils {
    public static LocalDateTime parseDateTime(String dateStr, boolean isStart) {
        if (dateStr == null || dateStr.isEmpty()) {
            return null;
        }
        // 判断字符串是否包含时分秒
        if (dateStr.length() == 10) {  // 格式为 yyyy-MM-dd
            dateStr += (isStart ? " 00:00:00" : " 23:58:59");    // 拼接默认时间 00:00:00
        }

        // 定义日期时间格式化器

        // 解析字符串为 LocalDateTime
        return LocalDateTime.parse(dateStr, FrameworkConst.DateTimes.DATE_TIME_FORMAT);
    }

    public static String toStr(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        return dateTime.format(FrameworkConst.DateTimes.DATE_TIME_FORMAT);
    }

    private static final ZoneId SERVER_ZONE = ZoneId.systemDefault();

    public static LocalDateTime utcToLocalDateTime(String utcTime) {
        // 处理带时区偏移的时间
        OffsetDateTime offsetDateTime = OffsetDateTime.parse(utcTime);
        return offsetDateTime.atZoneSameInstant(SERVER_ZONE).toLocalDateTime();
    }


    public static LocalDateTime fromStr(String dateTimeStr) {
        if (dateTimeStr == null) {
            return null;
        }
        return LocalDateTime.parse(dateTimeStr, FrameworkConst.DateTimes.DATE_TIME_FORMAT);
    }

    // 新增方法：将 LocalDateTime 转换为时间戳（毫秒）
    public static Long toTimestampMillis(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        // 转换为 UTC 时间戳（毫秒）
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    // 新增方法：将 LocalDateTime 转换为时间戳（秒）
    public static Long toTimestampSecond(LocalDateTime dateTime) {
        if (dateTime == null) {
            return null;
        }
        // 转换为 UTC 时间戳（秒）
        return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli() / 1000;
    }

    /**
     * 将10位Unix时间戳（单位：秒）转换为LocalDateTime
     *
     * @param epochSecond Unix时间戳（秒）
     * @return LocalDateTime（使用系统默认时区）
     */
    public static LocalDateTime toLongMillis(Long epochMilli) {
        if (null == epochMilli || epochMilli <= 0L) {
            return null;
        }
        return LocalDateTime.ofInstant(Instant.ofEpochMilli(epochMilli), ZoneId.systemDefault());
    }

    /**
     * 将10位Unix时间戳（单位：秒）转换为LocalDateTime
     *
     * @param epochSecond Unix时间戳（秒）
     * @return LocalDateTime（使用系统默认时区）
     */
    public static LocalDateTime toLongSeconds(Long epochSecond) {
        if (null == epochSecond || epochSecond <= 0L) {
            return null;
        }
        return LocalDateTime.ofInstant(Instant.ofEpochSecond(epochSecond), ZoneId.systemDefault());
    }

    public static Boolean betweenLimit(LocalDateTime start, LocalDateTime val, LocalDateTime end) {
        if (val == null) {
            return false;
        }
        boolean startOK = null == start || !val.isBefore(start);
        boolean endOK = null == end || !val.isAfter(end);
        return startOK && endOK;
    }

    /**
     * 时间差
     */
    public static TimeDifference calculateDifference(LocalDateTime start, LocalDateTime end) {
        // 计算毫秒差
        long diffMs = Math.abs(ChronoUnit.MILLIS.between(start, end));

        // 逐级转换
        long days = diffMs / (1000 * 60 * 60 * 24);
        long hours = (diffMs % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60);
        long minutes = (diffMs % (1000 * 60 * 60)) / (1000 * 60);
        long seconds = (diffMs % (1000 * 60)) / 1000;
        long ms = diffMs % 1000;

        return new TimeDifference(days, hours, minutes, seconds, ms);
    }


    /**
     * 优雅的时间差格式化 - 基于枚举配置
     */
    /**
     * 最简格式化
     */
    public static String format(TimeDifference diff, Function<EnumTimeUnit, String> unitLabelFormat) {
        if (diff == null) return "0" + unitLabelFormat.apply(EnumTimeUnit.SECOND);
        return Arrays.stream(EnumTimeUnit.values())
                .filter(u -> u.getPropInDiff() != null)
                .map(u -> toPart(u, u.getPropInDiff().apply(diff), unitLabelFormat))
                .filter(Objects::nonNull)
                .collect(Collectors.joining());
    }

    private static String toPart(EnumTimeUnit unit, Long value, Function<EnumTimeUnit, String> unitLabelFormat) {
        return value != null && value > 0 ? value + unitLabelFormat.apply(unit) : null;
    }
}
